package websocket

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/jn-qq/go-tools/data"
	"github.com/google/uuid"
	"github.com/gorilla/websocket"
	"github.com/mitchellh/mapstructure"
	"log"
	"maps"
	"net/http"
	"net/url"
	"slices"
	"strings"
	"time"
	"vector/control/sse"
	"vector/tools"
)

type AICanvas struct {
	content      string
	provinceName string
	intentName   string
	appId        string
	appSecret    string
	bodyId       string
	versionId    string
	startId      string
	sessionId    string
	appSessionId string
	debug        bool
	children     []*sse.LingXiDialogueResult
	resultData   map[string]any
}

func (aic *AICanvas) NewTaskData(row map[string]any) error {
	// 复制任务数据避免修改原数据
	aic.resultData = maps.Clone(row)
	// 从输入中提取问题、省份、意图
	filedValues, err := tools.FindStringFromMapAny(aic.resultData, "问题", "省份", "意图", "sessionId")
	if err != nil {
		return err
	}
	aic.content, aic.provinceName, aic.intentName = filedValues[0], filedValues[1], filedValues[2]

	// 设置debug信息
	aic.debug = tools.Config.AiCanvas.Debug

	sense := aic.intentName
	if strings.Contains(aic.intentName, "|") {
		senseList := strings.Split(aic.intentName, "|")
		aic.intentName, sense = senseList[0], senseList[1]
		aic.debug = true
	}
	// 根据意图名称获取画布信息
	aic.appId, aic.appSecret, aic.bodyId, aic.startId, aic.versionId, err = tools.Config.AiCanvas.FindCanvasInfo(sense)
	if err != nil {
		return err
	}

	// 检查参数
	if aic.bodyId == "" || aic.startId == "" {
		return fmt.Errorf("必要参数为空: bodyId/startId不能为空")
	}

	if aic.debug && aic.versionId == "" {
		return fmt.Errorf("必要参数为空: debug模式下versionId不能为空")
	}

	if !aic.debug && (aic.appId == "" || aic.appSecret == "") {
		return fmt.Errorf("必要参数为空: 非debug模式下appId和appSecret不能为空")
	}

	if filedValues[3] != "" {
		aic.sessionId = filedValues[3]
	} else {
		aic.sessionId = uuid.NewString()
	}

	return nil
}

func (aic *AICanvas) Do() {
	// 获取账号信息
	provinceCode, phone, authcode, err := tools.Config.Account.GetAccount(aic.provinceName)
	if err != nil {
		aic.resultData["备注"] = "获取账号信息异常:" + err.Error()
		return
	}
	aic.children = make([]*sse.LingXiDialogueResult, 0)

	for _, question := range strings.Split(aic.content, "\n") {
		question = strings.TrimSpace(question)
		if question == "" {
			// 跳过空行
			continue
		}
		child := new(sse.LingXiDialogueResult)
		aic.children = append(aic.children, child)
		child.Question = question
		traceId := uuid.NewString()
		child.TraceId = traceId
		child.SessionId = aic.sessionId
		child.Intent = aic.intentName

		// 构建请求入参
		payload, err := aic.buildPayload(question, provinceCode, phone, authcode, traceId)
		if err != nil {
			child.ErrMessage = "构建请求参数异常:" + err.Error()
			break
		}

		startTime := time.Now()

		newUrl := aic.CreateURL()
		header := aic.CreateHeader()

		// 建立WebSocket连接
		conn, _, err := websocket.DefaultDialer.Dial(newUrl, header)
		if err != nil {
			child.ErrMessage = "WebSocket连接异常:" + err.Error()
			break
		}
		defer conn.Close()

		// 发送请求
		if err := conn.WriteMessage(websocket.TextMessage, payload); err != nil {
			child.ErrMessage = "发送消息异常:" + err.Error()
			break
		}

		for {
			_, message, err := conn.ReadMessage()
			if err != nil {
				if !aic.debug && err.Error() == "websocket: close 1000 (normal)" {
					break
				}
				child.ErrMessage = "接收消息异常:" + err.Error()
				return
			}

			messageString := strings.TrimSpace(string(message))
			if messageString == "" {
				continue
			}
			//fmt.Println("接收到消息:", messageString)

			var response aiCanvasResponse
			if err := json.Unmarshal([]byte(messageString), &response); err != nil {
				child.ErrMessage = "解析响应异常(aiCanvasResponse):" + err.Error()
				break
			}

			if response.Header.Code != 0 {
				child.ErrMessage = "WebSocket响应异常:" + response.Header.Message
				break
			}
			if response.Header.Status == 2 {
				child.Status = "2"
				// 结束
				break
			}

			// 获取会话ID
			if aic.appSessionId == "" && response.Payload.SessionId != "" {
				aic.appSessionId = response.Payload.SessionId
			}

			if response.Payload.Output != nil && strings.TrimSpace(response.Payload.Output.Payload.Text) != "" {
				// 主要业务处理
				responseTxt := strings.TrimSpace(response.Payload.Output.Payload.Text)
				var aiCB aiCanvasBody
				err = json.Unmarshal([]byte(responseTxt), &aiCB)
				if err != nil {
					continue
				}

				switch aiCB.TxtType {
				case "txt":
					child.Message += aiCB.Message()
				case "cardList", "card":
					cardList, err := aiCB.CardList()
					if err != nil {
						child.ErrMessage = "解析响应异常(card):" + err.Error()
						break
					}
					for _, card := range cardList {
						switch card.Cardnumber {
						case "333":
							if card.Data.Msg != "" {
								child.Message += card.Data.Msg
							} else {
								continue
							}
						case "8060":
							child.ThinkList = append(
								child.ThinkList,
								fmt.Sprintf("%s(%s)",
									card.Data.Msg,
									data.TernaryExpression(card.Data.Success, "true", "false"),
								),
							)
						case "9999", "-1000":
							continue
						default:
							if !slices.Contains(child.UniqueId, card.CardId()) {
								child.CardList = append(child.CardList, card)
							}
						}
					}
				case "bubbleList", "bubble":
					barList, err := aiCB.BarList()
					if err != nil {
						child.ErrMessage = "解析响应异常(bar):" + err.Error()
						break
					}
					for _, bar := range barList {
						if !slices.Contains(child.UniqueId, bar.BarId()) {
							child.Barcontentlist = append(child.Barcontentlist, bar)
						}
					}
				case "think":
					child.ThinkList = append(child.ThinkList, aiCB.Data.(map[string]any)["txt"].(string)+"(action)")
				default:
					child.ErrMessage = "未知消息类型：" + aiCB.TxtType
				}
			}

			// 添加超时机制，避免无限等待
			if time.Since(startTime) > 5*time.Minute {
				child.ErrMessage = "WebSocket响应超时"
				break
			}
		}

	}

}

func (aic *AICanvas) Result() map[string]any {
	var resList []map[string]any
	for _, child := range aic.children {
		resList = append(resList, child.ToMap())
	}
	aic.resultData["child"] = resList
	return maps.Clone(aic.resultData)
}

// CreateURL 生成URL,拼接API网关核心鉴权签名信息
func (aic *AICanvas) CreateURL() string {
	if aic.debug {
		return fmt.Sprintf(
			"%s://%s:%d%s",
			tools.Config.AiCanvas.Scheme,
			tools.Config.AiCanvas.Host,
			tools.Config.AiCanvas.Port,
			tools.Config.AiCanvas.DebugPath,
		)
	}
	// 生成RFC1123格式的时间戳
	date := time.Now().UTC().Format(time.RFC1123)

	// 拼接字符串
	// 注意：换行符在 Go 中也是 \n
	signatureOrigin := fmt.Sprintf(
		"host: %s\ndate: %s\n%s %s HTTP/1.1",
		tools.Config.AiCanvas.Host, date,
		http.MethodGet,
		tools.Config.AiCanvas.Path,
	)

	// 进行 hmac-sha256 进行加密
	h := hmac.New(sha256.New, []byte(aic.appSecret))
	h.Write([]byte(signatureOrigin))
	signatureSha := h.Sum(nil)

	// 对加密结果进行 base64 编码
	signatureShaBase64 := base64.StdEncoding.EncodeToString(signatureSha)

	// 构建 authorization_origin 字符串
	authorizationOrigin := fmt.Sprintf(
		`hmac api_key="%s", algorithm="hmac-sha256", headers="host date request-line", signature="%s"`,
		aic.appId, signatureShaBase64,
	)

	// 对 authorization_origin 进行 base64 编码
	authorization := base64.StdEncoding.EncodeToString([]byte(authorizationOrigin))

	// 将请求的鉴权参数组合为 map (Go 中的字典等价物)
	v := map[string]string{
		"authorization": authorization,
		"date":          date,
		"host":          tools.Config.AiCanvas.Host,
		"bodyId":        aic.bodyId,
	}

	// 构建基础 URL
	baseURL := fmt.Sprintf(
		"%s://%s:%d%s",
		tools.Config.AiCanvas.Scheme,
		tools.Config.AiCanvas.Host,
		tools.Config.AiCanvas.Port,
		tools.Config.AiCanvas.Path,
	)

	// 创建 URL 对象以便安全地添加查询参数
	u, _ := url.Parse(baseURL)

	// 构建查询参数
	q := u.Query()
	for key, value := range v {
		q.Set(key, value)
	}
	u.RawQuery = q.Encode()

	//fmt.Println("URL:", u.String())

	// 拼接鉴权参数，生成 URL
	return u.String()
}

func (aic *AICanvas) CreateHeader() http.Header {
	if aic.debug {
		var header = http.Header{}
		header.Add("Cookie", "SESSION="+tools.Config.AiCanvas.Cookie["SESSION"])
		return header
	}
	return nil
}

func (aic *AICanvas) Reset() {
	clear(aic.resultData)
	aic.content = ""
	aic.provinceName = ""
	aic.intentName = ""
	aic.bodyId = ""
	aic.versionId = ""
	aic.startId = ""
	aic.sessionId = ""
	aic.children = nil
	aic.appId = ""
	aic.appSecret = ""
	aic.appSessionId = ""
}

// buildPayload 构建WebSocket请求参数
func (aic *AICanvas) buildPayload(question, provinceCode, phone, authCode, traceId string) ([]byte, error) {
	// 获取默认配置
	body := tools.Config.AiCanvas.GetBody()
	maps.Copy(body, map[string]string{
		"question":      question,
		"phoneNumber":   phone,
		"provinceCode":  provinceCode,
		"authCode":      authCode,
		"sessionId":     aic.sessionId,
		"questionId":    aic.sessionId,
		"traceId":       traceId,
		"intentName":    aic.intentName,
		"chatbotIntent": aic.intentName,
	})

	header := tools.Config.AiCanvas.GetHeader()
	var newHeader = map[string]any{}
	if aic.debug {
		newHeader = map[string]any{
			"bodyId":    data.TernaryExpression(header["bodyId"] != "", header["bodyId"], aic.bodyId),
			"versionId": data.TernaryExpression(header["versionId"] != "", header["versionId"], aic.versionId),
			"traceId":   "work-flow-node-debug_" + traceId,
			"mode":      1,
		}
	} else {
		newHeader = map[string]any{
			"bodyId":  data.TernaryExpression(header["bodyId"] != "", header["bodyId"], aic.bodyId),
			"appId":   data.TernaryExpression(header["appId"] != "", header["appId"], aic.appId),
			"traceId": traceId,
			"mode":    0,
		}
	}

	payload := map[string]any{
		"header": newHeader,
		"payload": map[string]any{
			"debug":     aic.debug,
			"sessionId": aic.appSessionId,
			"input": map[string]any{
				aic.startId: map[string]any{
					"req": body,
				},
			},
		},
	}

	return json.Marshal(payload)
}

// aiCanvasResponse 画布输出消息响应结构体
type aiCanvasResponse struct {
	Header struct {
		Code    int    `json:"code"`
		Message string `json:"message"`
		Status  int    `json:"status"`
	} `json:"header"`
	Payload struct {
		State *struct {
			NodeCode     string `json:"nodeCode"`
			StateContent struct {
				Payload struct {
					Txt string `json:"txt"`
				} `json:"payload"`
			} `json:"stateContent"`
			StateType string `json:"stateType"`
		} `json:"state"`
		Output *struct {
			Node    string `json:"node"`
			Payload struct {
				Text string `json:"text"`
			} `json:"payload"`
		} `json:"output"`
		SessionId string `json:"sessionId"`
	} `json:"payload"`
}

// aiCanvasBody 具体用户消息体结构体
type aiCanvasBody struct {
	TxtType string `json:"type"`
	Data    any    `json:"data"`
}

func (a *aiCanvasBody) Message() string {
	return a.Data.(string)
}

func (a *aiCanvasBody) CardList() ([]sse.Card, error) {
	var cardList []sse.Card
	var err error
	a.lx()
	switch a.TxtType {
	case "cardList":
		err = mapstructure.Decode(a.Data, &cardList)
	case "card":
		var card sse.Card
		err = mapstructure.Decode(a.Data, &card)
		cardList = append(cardList, card)
	default:
		err = errors.New("未知的txtType")
	}

	if err != nil {
		log.Println("cardList转换错误", err, "\n数据：", a.Data)
		return nil, err
	}
	return cardList, nil
}

func (a *aiCanvasBody) BarList() ([]sse.Bar, error) {
	var barList []sse.Bar
	var err error
	a.lx()
	switch a.TxtType {
	case "bubbleList":
		err = mapstructure.Decode(a.Data, &barList)
	case "bubble":
		var bar sse.Bar
		err = mapstructure.Decode(a.Data, &bar)
		barList = append(barList, bar)
	}

	if err != nil {
		log.Println("barList转换错误", err, "\n数据：", a.Data)
		return nil, err
	}
	return barList, nil
}

func (a *aiCanvasBody) lx() {
	switch t := a.Data.(type) {
	case string:
		if a.TxtType == "cardList" || a.TxtType == "bubbleList" {
			var crash []map[string]any
			_ = json.Unmarshal([]byte(t), &crash)
			a.Data = crash
		} else {
			var crash map[string]any
			_ = json.Unmarshal([]byte(t), &crash)
			a.Data = crash
		}
	default:
		return
	}
}
